﻿using blacksoft.Constantes;
using blacksoft.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Transactions;
using System.Web;
using System.Web.Mvc;

namespace blacksoft.Controllers
{
    public class ComprarPasajeController : Controller
    {

        private inf245travelbusEntities db = new inf245travelbusEntities();
        private decimal porc_igv = (decimal)0.19;
        private decimal tipo_cambio = (decimal)2.8;
        //
        // GET: /ComprarPasaje/
        public ActionResult BuscarProgramacion()
        {
            var model = new GenerateReservaFilterModel();
            var ListRutaActiva = db.Ruta.ToList().Where(c => c.Estado == "AC").ToList();
            var Origen = ListRutaActiva.Select(c => new { c.Origen }).Distinct().ToList();
            var Destino = ListRutaActiva.Select(c => new { c.Destino }).Distinct().ToList();
            model.ListOrigen = (from c in Origen select new SelectListItem() { Text = c.Origen, Value = c.Origen }).ToList();
            model.ListDestino = (from c in Destino select new SelectListItem() { Text = c.Destino, Value = c.Destino }).ToList();


            return View(model);
        }


        public ActionResult Programacion(string Origen, string Destino, string TipoViaje, string FechaSalida, string FechaLlegada)
        {
            DateTime _FechaSalida = new DateTime();
            DateTime _FechaRegreso;
            try
            {
                _FechaSalida = DateTime.ParseExact(FechaSalida, "dd/MM/yyyy", null);
            }
            catch { return RedirectToAction("Index", "INT_Principal"); };
            //catch { return RedirectToRoute("/"); }
            DateTime _FechaSalida_2 = _FechaSalida.AddDays(1);
            var model = new GenerateReservaModel();

            //var listaProgramacionFormateada = (from c in db.ProgramacionViaje select new { c.IDProgramacionViaje, FechaSalida = Convert.ToDateTime(c.FechaSalida.Value.ToString("dd/MM/yyyy")), FechaLlegada = Convert.ToDateTime(c.FechaLlegada.Value.ToString("dd/MM/yyyy")), c.Descripcion, CapacidadPasajeros = c.CapacidadPasajeros.Value, Precio = c.Precio.Value, c.IdRuta_x_UnidadTransporte, c.Estado, TipoServicio = c.TipoServicio.Value }).ToList();
            var listaProgramacionFormateada = db.ProgramacionViaje.Where(c => c.FechaSalida.Value >= _FechaSalida && c.FechaSalida.Value < _FechaSalida_2).ToList();

            var listaFiltrada = (from prog in listaProgramacionFormateada
                                 join ruta_unid in db.Ruta_x_UnidadTransporte on prog.IdRuta_x_UnidadTransporte equals ruta_unid.IdRuta_x_UnidadTransporte
                                 join ruta in db.Ruta on ruta_unid.IDRuta.Value equals ruta.IDRuta
                                 where ruta.Origen.Trim() == Origen && ruta.Destino.Trim() == Destino /*&& prog.FechaSalida == _FechaSalida*/ && ruta.Estado == "AC"
                                 select new ProgramacionDisponible { IdProgramcionViaje = prog.IDProgramacionViaje, Precio = prog.Precio.Value, DescriptionTipoServicio = (prog.TipoServicio == 1) ? "Economico" : "VIP", FechaSalida = prog.FechaSalida.Value, Origen = ruta.Origen, Destino = ruta.Destino }).ToList();

            if (!TipoViaje.Equals("IDA"))
            {
                _FechaRegreso = Convert.ToDateTime(FechaLlegada);
                DateTime _FechaRegreso_2 = _FechaRegreso.AddDays(1);

                var listaProgramacionFormateadaVuelta = db.ProgramacionViaje.Where(c => c.FechaSalida.Value >= _FechaRegreso && c.FechaSalida.Value < _FechaRegreso_2).ToList();

                var listaFiltradaVuelta = (from prog in listaProgramacionFormateadaVuelta
                                           join ruta_unid in db.Ruta_x_UnidadTransporte on prog.IdRuta_x_UnidadTransporte equals ruta_unid.IdRuta_x_UnidadTransporte
                                           join ruta in db.Ruta on ruta_unid.IDRuta.Value equals ruta.IDRuta
                                           where ruta.Origen == Destino && ruta.Destino == Origen /*&& prog.FechaSalida.Value >= _FechaRegreso*/ && ruta.Estado == "AC"
                                           select new ProgramacionDisponible { IdProgramcionViaje = prog.IDProgramacionViaje, Precio = prog.Precio.Value, DescriptionTipoServicio = (prog.TipoServicio.Value == 1) ? "Economico" : "VIP", FechaSalida = prog.FechaSalida.Value, Origen = ruta.Origen, Destino = ruta.Destino }).ToList();
                model.listaProgramacionViajeVuelta = listaFiltradaVuelta.ToList<ProgramacionDisponible>();
            }
            model.TipoReserva = TipoViaje;
            model.listaProgramacionViaje = listaFiltrada.ToList<ProgramacionDisponible>();
            return View(model);
        }



        public JsonResult listarAsientosNoDisponibles(int idProgramacionViaje)
        {
            var datosProgramacion = db.ProgramacionViaje.ToList().Where(c => c.IDProgramacionViaje == idProgramacionViaje).First();
            var listaPasajes = (from c in db.Pasaje join r in db.Reserva on c.IDReserva equals r.IDReserva where c.IDProgramacionViaje == idProgramacionViaje && r.Estado == "AC" select new { c.NroAsiento }).ToList();
            var listaPasajesPago = (from c in db.Pasaje join r in db.Reserva on c.IDReserva equals r.IDReserva where c.IDProgramacionViaje == idProgramacionViaje && r.Estado == "CA" select new { c.NroAsiento }).ToList();
            return Json(new { listaAsientosReservados = listaPasajes, servicio = (datosProgramacion.TipoServicio.Value == 1) ? "Economico" : "VIP", precio = datosProgramacion.Precio, asientoPagado = listaPasajesPago });
        }

        public JsonResult listarAsientosNoDisponiblesVuelta(int idProgramacionViaje)
        {
            var datosProgramacion = db.ProgramacionViaje.ToList().Where(c => c.IDProgramacionViaje == idProgramacionViaje).First();
            var listaPasajes = (from c in db.Pasaje join r in db.Reserva on c.IDReserva equals r.IDReserva where c.IDProgramacionViaje == idProgramacionViaje && r.Estado == "AC" select new { c.NroAsiento }).ToList();
            var listaPasajesPago = (from c in db.Pasaje join r in db.Reserva on c.IDReserva equals r.IDReserva where c.IDProgramacionViaje == idProgramacionViaje && r.Estado == "CA" select new { c.NroAsiento }).ToList();
            return Json(new { listaAsientosReservados = listaPasajes, servicio = (datosProgramacion.TipoServicio.Value == 1) ? "Economico" : "VIP", precio = datosProgramacion.Precio, asientoPagado = listaPasajesPago });
        }

        public JsonResult getDatosPasajeroXDNI(string NroDni)
        {
            var datosPasajero = (from pe in db.Persona.ToList()
                                 where pe.DNI == NroDni
                                 select new { pe.Nombre, pe.ApellidoPaterno, pe.ApellidoMaterno, FechaNacimiento = pe.FechaNacimiento.Value.ToString("dd/MM/yyyy").ToString(), Telefono = pe.Telefono.Value, pe.Email, pe.Direccion }).ToList();
            if (datosPasajero.Any())
                return Json(new { any = 1, datos = datosPasajero.First() });
            else
                return Json(new { any = 0 });
        }

        public JsonResult agregarPasajeroTemporal(string nombrePasajero, string apPaternoPasajero, string apMaternoPasajero, string dniPasajero, string emailPasajero, string direccionPasajero, string fecNacimientoPasajero, string telefonoPasajero, int asiento, int asientoVuelta, string refrigerio, string almuerzo, string tipoDocumento)
        {
            List<PasajeroModel> listaPasajero;
            if (Session["PASAJEROS_REGISTRADOS_TEMP_LOGIN"] == null)
                listaPasajero = new List<PasajeroModel>();
            else
                listaPasajero = (List<PasajeroModel>)Session["PASAJEROS_REGISTRADOS_TEMP_LOGIN"];
            listaPasajero.Add(new PasajeroModel() { Nombre = nombrePasajero, ApellidoPaterno = apPaternoPasajero, ApellidoMaterno = apMaternoPasajero, DNI = dniPasajero, Email = emailPasajero, FechaNacimiento = fecNacimientoPasajero, Telefono = telefonoPasajero, FechaRegistro = DateTime.Now.ToShortDateString(), NroAsiento = asiento, NroAsientoVuelta = asientoVuelta, Refrigerio = refrigerio, Almuerzo = almuerzo, TipoDocumentos = tipoDocumento });
            Session["PASAJEROS_REGISTRADOS_TEMP_LOGIN"] = listaPasajero;
            return Json(new { result = "1", mensajeRespuesta = "Se agrego al pasajero Satisfactoriamente" });
        }


        public JsonResult generarReserva(int idProgramacionViaje, int idProgramacionViajeVuelta)
        {
            using (TransactionScope oTransaction = new TransactionScope())
            {
                try
                {
                    var listadoPasajeros = (List<PasajeroModel>)Session["PASAJEROS_REGISTRADOS_TEMP_LOGIN"];
                    var datosProgramacion = db.ProgramacionViaje.ToList().Where(c => c.IDProgramacionViaje == idProgramacionViaje).First();
                    var reservaEntity = new Reserva();
                    var reservaEntityVuelta = new Reserva();
                    //reservaEntity.Origen = "LIMA";
                    //reservaEntity.Destino = "CUZCO";
                    reservaEntity.FechaSalida = datosProgramacion.FechaSalida.Value;
                    reservaEntity.FechaRetorno = datosProgramacion.FechaLlegada.Value;
                    reservaEntity.FechaLimite = DateTime.Now.AddDays(1);
                    reservaEntity.FechaRegistro = DateTime.Now;
                    reservaEntity.NumeroPasajeros = listadoPasajeros.Count();
                    reservaEntity.Estado = SystemField.ESTATE_REGISTER_ACTIVE;
                    db.Reserva.Add(reservaEntity);
                    db.SaveChanges();


                    if (idProgramacionViajeVuelta != 0)
                    {
                        var datosProgramacionVuelta = db.ProgramacionViaje.ToList().Where(c => c.IDProgramacionViaje == idProgramacionViajeVuelta).First();
                        reservaEntityVuelta.FechaSalida = datosProgramacionVuelta.FechaSalida.Value;
                        reservaEntityVuelta.FechaRetorno = datosProgramacionVuelta.FechaLlegada.Value;
                        reservaEntityVuelta.FechaLimite = DateTime.Now.AddDays(2);
                        reservaEntityVuelta.FechaRegistro = DateTime.Now;
                        reservaEntityVuelta.NumeroPasajeros = listadoPasajeros.Count();
                        reservaEntityVuelta.Estado = SystemField.ESTATE_REGISTER_ACTIVE;
                        reservaEntityVuelta.IdAnexo = reservaEntity.IDReserva;
                        db.Reserva.Add(reservaEntityVuelta);
                        db.SaveChanges();
                    }


                    bool getFirstPasajero = false;
                    int idPersonaRegistradaPrimeraFila = 0;
                    foreach (var item in listadoPasajeros)
                    {
                        var pasajeVueltaOcupada = (from c in db.Pasaje.ToList() where c.NroAsiento == item.NroAsiento && c.IDProgramacionViaje == idProgramacionViaje select c).ToList();
                        if (pasajeVueltaOcupada.Any())
                        {
                            Session["PASAJEROS_REGISTRADOS_TEMP_LOGIN"] = null;
                            throw new Exception("Uno de los asientos seleccionados (Viaje ida) ya se encuentra ocupado. Su reserva no se puede generar");
                        }

                        if (idProgramacionViajeVuelta != 0)
                        {
                            var pasajeVueltaOcupadaVuelta = (from c in db.Pasaje.ToList() where c.NroAsiento == item.NroAsientoVuelta && c.IDProgramacionViaje == idProgramacionViajeVuelta select c).ToList();
                            if (pasajeVueltaOcupadaVuelta.Any())
                            {
                                Session["PASAJEROS_REGISTRADOS_TEMP_LOGIN"] = null;
                                throw new Exception("Uno de los asientos seleccionados (Viaje retorno) ya se encuentra ocupado. Su reserva no se puede generar");
                            }
                        }


                        var personaEntity = new Persona();
                        var validaExistePersonaTable = (from c in db.Persona.ToList() where c.DNI == item.DNI select c);
                        if (validaExistePersonaTable.Any())
                        {
                            personaEntity.IDPersona = validaExistePersonaTable.First().IDPersona;
                        }
                        else
                        {
                            personaEntity.DNI = item.DNI;
                            personaEntity.Nombre = item.Nombre;
                            personaEntity.ApellidoPaterno = item.ApellidoPaterno;
                            personaEntity.ApellidoMaterno = item.ApellidoMaterno;
                            personaEntity.Direccion = item.Direccion;
                            personaEntity.Email = item.Email;
                            personaEntity.Telefono = Convert.ToInt32(item.Telefono);
                            personaEntity.FechaNacimiento = Convert.ToDateTime(item.FechaNacimiento);
                            personaEntity.Estado = SystemField.ESTATE_REGISTER_ACTIVE;
                            personaEntity.TipoPersona = SystemField.ID_PERSONA_PASAJERO_COMUN;
                            personaEntity.PuntosAcumulados = 0;
                            personaEntity.tipoDocumento = item.TipoDocumentos;



                            db.Persona.Add(personaEntity);
                            db.SaveChanges();

                            db.Usuario.Add(new Usuario() { Nombre = item.DNI, Contraseña = SetHash("123"), IDPersona = personaEntity.IDPersona, IDPerfil = SystemField.ID_USUARIO_PERSONA_COMUN });
                            db.SaveChanges();
                        }

                        if (!getFirstPasajero)
                        {
                            idPersonaRegistradaPrimeraFila = personaEntity.IDPersona;
                            getFirstPasajero = true;
                        }

                        var pasajeEntity = new Pasaje();
                        pasajeEntity.Nombre = item.Nombre;
                        pasajeEntity.ApellidoPaterno = item.ApellidoPaterno;
                        pasajeEntity.ApellidoMaterno = item.ApellidoMaterno;
                        pasajeEntity.DNI = item.DNI;
                        pasajeEntity.NroAsiento = item.NroAsiento;
                        pasajeEntity.Estado = SystemField.ESTATE_REGISTER_ACTIVE;
                        pasajeEntity.IDProgramacionViaje = idProgramacionViaje;
                        pasajeEntity.IDPersona = personaEntity.IDPersona;
                        pasajeEntity.IDReserva = reservaEntity.IDReserva;
                        pasajeEntity.MontoCosto = 0;
                        pasajeEntity.MontoDescuento = 0;
                        pasajeEntity.MontoPago = 0;
                        pasajeEntity.Almuerzo = item.Almuerzo;
                        pasajeEntity.Refrigerio = item.Refrigerio;
                        db.Pasaje.Add(pasajeEntity);
                        db.SaveChanges();

                        if (idProgramacionViajeVuelta != 0)
                        {
                            var pasajeEntityVuelta = new Pasaje();
                            pasajeEntityVuelta.Nombre = item.Nombre;
                            pasajeEntityVuelta.ApellidoPaterno = item.ApellidoPaterno;
                            pasajeEntityVuelta.ApellidoMaterno = item.ApellidoMaterno;
                            pasajeEntityVuelta.DNI = item.DNI;
                            pasajeEntityVuelta.NroAsiento = item.NroAsientoVuelta;
                            pasajeEntityVuelta.Estado = SystemField.ESTATE_REGISTER_ACTIVE;
                            pasajeEntityVuelta.IDProgramacionViaje = idProgramacionViajeVuelta;
                            pasajeEntityVuelta.IDPersona = personaEntity.IDPersona;
                            pasajeEntityVuelta.IDReserva = reservaEntityVuelta.IDReserva;
                            db.Pasaje.Add(pasajeEntityVuelta);
                            db.SaveChanges();
                        }
                    }

                    var reserva = db.Reserva.ToList().Where(c => c.IDReserva == reservaEntity.IDReserva).First();
                    reserva.IDPersona = idPersonaRegistradaPrimeraFila;
                    if (idProgramacionViajeVuelta != 0)
                    {
                        var reservaVuelta = db.Reserva.ToList().Where(c => c.IDReserva == reservaEntityVuelta.IDReserva).First();
                        reservaVuelta.IDPersona = idPersonaRegistradaPrimeraFila;
                    }
                    db.SaveChanges();

                    Session["PASAJEROS_REGISTRADOS_TEMP_LOGIN"] = null;
                    oTransaction.Complete();
                    Session["MODVENTA_IDReserva"] = reservaEntity.IDReserva;
                    return Json(new { result = "1", mensajeRespuesta = "Se genero su reserva satisfactoriamente el numero de Reserva es : " + reservaEntity.IDReserva });
                }
                catch (Exception ex)
                {
                    oTransaction.Dispose();
                    return Json(new { result = "0", mensajeRespuesta = ex.Message.ToString() });
                }
            }
        }



        private static string SetHash(string a)
        {
            using (MD5 md5Hash = MD5.Create())
            {
                return GetMd5Hash(md5Hash, a);
            }
        }


        public static string GetMd5Hash(MD5 md5Hash, string input)
        {
            // Convert the input string to a byte array and compute the hash.
            byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));
            // Create a new Stringbuilder to collect the bytes
            // and create a string.
            StringBuilder sBuilder = new StringBuilder();
            // Loop through each byte of the hashed data 
            // and format each one as a hexadecimal string.
            for (int i = 0; i < data.Length; i++)
            {
                sBuilder.Append(data[i].ToString("x2"));
            }
            // Return the hexadecimal string.
            return sBuilder.ToString();
        }


        public ActionResult ReserveConfirmation()
        {
            if (Session["MODVENTA_IDReserva"] != null)
            {
                //ID de Reserva a mostrar
                ViewBag.IDReserva = ((int)Session["MODVENTA_IDReserva"]).ToString();

                //////////////////////////////////////////////////////////////////
                //Buscar reserva con el IDReserva seleccionado
                int aux_IDReserva = (int)Session["MODVENTA_IDReserva"];
                Reserva reserva = db.Reserva.Find(aux_IDReserva);
                //Listar pasajes para la reserva seleccionada
                var aux_lst = new List<Pasaje>();
                var qry_pasajes = from p in db.Pasaje
                                  where p.IDReserva == aux_IDReserva
                                  select p;
                aux_lst.AddRange(qry_pasajes.Distinct());
                reserva.Pasaje = aux_lst;
                //////////////////////////////////////////////////////////////////


                return View(reserva);
            }

            //Si nunca se obtuvo el ID de la reserva no se realiza la operación: regreso a Index
            return RedirectToAction("BuscarProgramacion");
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult ReserveConfirmation(string rb)
        {
            return RedirectToAction("Payment");
        }


        public ActionResult Payment(string CJ_RUC)
        {
            if (Session["MODVENTA_IDReserva"] == null)
            {
                return RedirectToAction("BuscarProgramacion");
            }

            ART_Venta venta = new ART_Venta();

            var personas = from p in db.Persona
                           select p;

            if (!string.IsNullOrEmpty(CJ_RUC))
            {
                personas = personas.Where(s => s.RUC == CJ_RUC);
                ViewBag.CJ_RUC = personas.First().RUC;
                ViewBag.CJ_RazonSocial = personas.First().RazonSocial;
                ViewBag.CJ_Direccion = personas.First().Direccion;
                ViewBag.CJ_Telefono = personas.First().Telefono.ToString();
                ViewBag.CJ_Email = personas.First().Email;
                Session["MODVENTA_CJ"] = personas.First();
                Session["MODVENTA_CJ_RUC"] = CJ_RUC;
            }
            else
            {
                ViewBag.CJ_RUC = "";
                ViewBag.CJ_RazonSocial = "";
                ViewBag.CJ_Direccion = "";
                ViewBag.CJ_Telefono = "";
                ViewBag.CJ_Email = "";
            }

            //////////////////////////////////////////////////////////////////
            //Buscar reserva con el IDReserva seleccionado
            int aux_IDReserva = (int)Session["MODVENTA_IDReserva"];
            Reserva reserva = db.Reserva.Find(aux_IDReserva);
            //Listar pasajes para la reserva seleccionada
            var aux_lst = new List<Pasaje>();
            var qry_pasajes = from p in db.Pasaje
                              where p.IDReserva == aux_IDReserva
                              select p;
            //////////////////////////////////////////////////////////////////

            //////////////////////////////////////////////////////////////////
            //Obtener monto a pagar total por todos los pasajes
            decimal? monto_pago_total = 0;
            decimal? monto_descuento_total = 0;

            foreach (var pj in qry_pasajes)
            {
                //acumular pagos
                monto_pago_total += pj.ProgramacionViaje.Precio;

                //--------------------------------------DESCUENTOS-----------------------------------//
                //Buscar promocion asociada al viaje de cada pasaje
                var qry_promocion = from pv in db.ProgramacionViaje
                                    join pxpv in db.Promocion_ProgramacionViaje on pv.IDProgramacionViaje equals pxpv.IDProgramacionViaje
                                    join p in db.Promocion on pxpv.IdPromocion equals p.IdPromocion
                                    where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                    select new { p.FechaFin, p.FechaInicio, p.PorcentajeDescuento, p.PuntosRequeridos, p.TipoCliente };
                if (qry_promocion != null)
                {
                    //Por cada promocion, verificar la fecha de fin 
                    foreach (var prom in qry_promocion)
                    {
                        //Si es menor realizar descuento
                        if (prom.FechaInicio < DateTime.Now.Date && prom.FechaFin > DateTime.Now.Date)
                        {
                            //Buscar el tipo de persona/cliente para saber si la promoción es aplicable o no
                            Persona cliente = db.Persona.Find(pj.IDPersona);
                            //Verificar que el descuento se aplica al tipo de cliente
                            if (prom.TipoCliente == cliente.TipoPersona)
                            {
                                //si el cliente tiene puntaje para invertir
                                if (cliente.PuntosAcumulados >= prom.PuntosRequeridos)
                                {
                                    //acumular descuento
                                    monto_descuento_total += pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                    //si los descuentos acumulados superan al pago solo seran iguales a este en el caso extremo
                                    if (monto_descuento_total > monto_pago_total)
                                    {
                                        monto_descuento_total = monto_pago_total;
                                        break;
                                    }
                                }
                            }
                        }
                    }

                }
            }
            venta.MontoDescuento += Math.Round((decimal)monto_descuento_total, 2);
            venta.Total += monto_pago_total;
            venta.Vuelto += 0;
            //////////////////////////////////////////////////////////////////

            //------------------------------------------------------------------------------------------------------------------------------------//

            //////////////////////////////////////////////////////////////////
            //Buscar reserva de vuelta
            int aux2_idres = (int)Session["MODVENTA_IDReserva"];
            var qry_res_vuelta = from p in db.Reserva
                                 where p.IdAnexo == aux2_idres
                                 select p;
            if (qry_res_vuelta.Count() > 0)
            {
                //Asignarle los puntos asociados
                int aux2_idres_vuelta = qry_res_vuelta.First().IDReserva;
                //Listar pasajes para la reserva seleccionada
                var aux2_lst = new List<Pasaje>();
                var qry_pasajes2 = from p in db.Pasaje
                                   where p.IDReserva == aux2_idres_vuelta
                                   select p;
                //////////////////////////////////////////////////////////////////

                //////////////////////////////////////////////////////////////////
                //Obtener monto a pagar total por todos los pasajes
                decimal? monto_pago_total2 = 0;
                decimal? monto_descuento_total2 = 0;

                foreach (var pj in qry_pasajes2)
                {
                    //acumular pagos
                    monto_pago_total2 += pj.ProgramacionViaje.Precio;

                    //--------------------------------------DESCUENTOS-----------------------------------//
                    //Buscar promocion asociada al viaje de cada pasaje
                    var qry_promocion = from pv in db.ProgramacionViaje
                                        join pxpv in db.Promocion_ProgramacionViaje on pv.IDProgramacionViaje equals pxpv.IDProgramacionViaje
                                        join p in db.Promocion on pxpv.IdPromocion equals p.IdPromocion
                                        where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                        select new { p.FechaFin, p.FechaInicio, p.PorcentajeDescuento, p.PuntosRequeridos, p.TipoCliente };
                    if (qry_promocion != null)
                    {
                        //Por cada promocion, verificar la fecha de fin 
                        foreach (var prom in qry_promocion)
                        {
                            //Si es menor realizar descuento
                            if (prom.FechaInicio < DateTime.Now.Date && prom.FechaFin > DateTime.Now.Date)
                            {
                                //Buscar el tipo de persona/cliente para saber si la promoción es aplicable o no
                                Persona cliente = db.Persona.Find(pj.IDPersona);
                                //Verificar que el descuento se aplica al tipo de cliente
                                if (prom.TipoCliente == cliente.TipoPersona)
                                {
                                    //si el cliente tiene puntaje para invertir
                                    if (cliente.PuntosAcumulados >= prom.PuntosRequeridos)
                                    {
                                        //acumular descuento
                                        monto_descuento_total2 += pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                        //si los descuentos acumulados superan al pago solo seran iguales a este en el caso extremo
                                        if (monto_descuento_total2 > monto_pago_total2)
                                        {
                                            monto_descuento_total2 = monto_pago_total2;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                    }
                }
                venta.MontoDescuento += Math.Round((decimal)monto_descuento_total2, 2);
                venta.Total += monto_pago_total2;
                venta.Vuelto += 0;
            }
            //////////////////////////////////////////////////////////////////

            return View(venta);
        }


        // POST: /Venta/Payment
        // Para protegerse de ataques de publicación excesiva, habilite las propiedades específicas a las que desea enlazarse. Para obtener 
        // más información vea http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        //ClienteJ,
        public ActionResult Payment([Bind(Include = "IDVenta,IDNotaCredito,MontoDolares,MontoTarjeta,MontoNotaCredito,Total,MedioPago,MontoDescuento,MontoSoles,Vuelto")]ART_Venta venta, bool chbxNotaCred)
        {
            Persona aux_persona = new Persona();
            Venta aux_venta = new Venta();

            decimal? monto_pago_total = 0;
            decimal? monto_descuento_total = 0;
            if (ModelState.IsValid)
            {
                string CJ_RUC = (string)Session["MODVENTA_CJ_RUC"];
                //Buscar al cliente juridico
                var aux_per = from p in db.Persona
                              where CJ_RUC == p.RUC
                              select p;
                //Si el Cliente Empresa ya existe en el sistema, procesarlo
                if (aux_per.Count() > 0)
                {
                    //--------------------------------------PASAJES DE IDA-----------------------------------//
                    //Asignarle los puntos asociados
                    int aux_idres = (int)Session["MODVENTA_IDReserva"];
                    var qry_pjCJ = from p in db.Pasaje
                                   where p.IDReserva == aux_idres
                                   select p;
                    foreach (var pj in qry_pjCJ)
                    {
                        //--------------------------------------PUNTAJES-----------------------------------//
                        //búsqueda del puntaje a ganar
                        var puntosAGanar = from pv in db.ProgramacionViaje
                                           join rxt in db.Ruta_x_UnidadTransporte on pv.IdRuta_x_UnidadTransporte equals rxt.IdRuta_x_UnidadTransporte
                                           join r in db.Ruta on rxt.IDRuta equals r.IDRuta
                                           where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                           select r.PuntosAGanar;
                        //Suma de puntaje 
                        Persona empresa = db.Persona.Find(aux_per.First().IDPersona);
                        empresa.PuntosAcumulados += puntosAGanar.First();
                        db.Entry(empresa).State = EntityState.Modified;


                        //--------------------------------------DESCUENTOS-----------------------------------//
                        //acumular pagos
                        monto_pago_total += pj.ProgramacionViaje.Precio;
                        //Buscar promocion asociada al viaje de cada pasaje
                        var qry_promocion = from pv in db.ProgramacionViaje
                                            join pxpv in db.Promocion_ProgramacionViaje on pv.IDProgramacionViaje equals pxpv.IDProgramacionViaje
                                            join p in db.Promocion on pxpv.IdPromocion equals p.IdPromocion
                                            where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                            select new { p.FechaFin, p.FechaInicio, p.PorcentajeDescuento, p.PuntosRequeridos, p.TipoCliente };
                        if (qry_promocion != null)
                        {
                            //Por cada promocion, verificar la fecha de fin 
                            foreach (var prom in qry_promocion)
                            {
                                //Si es menor realizar descuento
                                if (prom.FechaInicio < DateTime.Now.Date && prom.FechaFin > DateTime.Now.Date)
                                {
                                    //Verificar que el descuento se aplica al tipo de cliente
                                    if (prom.TipoCliente == empresa.TipoPersona)
                                    {
                                        //si el cliente tiene puntaje para invertir
                                        if (empresa.PuntosAcumulados >= prom.PuntosRequeridos)
                                        {
                                            //acumular descuento
                                            monto_descuento_total += pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                            pj.MontoDescuento = pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                            empresa.PuntosAcumulados -= prom.PuntosRequeridos;
                                            db.Entry(empresa).State = EntityState.Modified;
                                            //si los descuentos acumulados superan al pago solo seran iguales a este en el caso extremo
                                            if (monto_descuento_total > monto_pago_total)
                                            {
                                                monto_descuento_total = monto_pago_total;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }

                        }

                        //-------------------------------MODIFICACIONES PASAJES-----------------------------//
                        pj.MontoCosto = pj.ProgramacionViaje.Precio;
                        pj.MontoPago = pj.MontoCosto - pj.MontoDescuento;
                        pj.Estado = "CA";
                        db.Entry(pj).State = EntityState.Modified;
                    }
                    //db.SaveChanges();

                    //-----------------------------------------------------------------PASAJES DE VUELTA-----------------------------------------------------//
                    //Buscar reserva de vuelta
                    int aux2_idres = (int)Session["MODVENTA_IDReserva"];
                    var qry_res_vuelta = from p in db.Reserva
                                         where p.IdAnexo == aux2_idres
                                         select p;
                    //
                    if (qry_res_vuelta.Count() > 0)
                    {
                        //Asignarle los puntos asociados
                        int aux2_idres_vuelta = qry_res_vuelta.First().IDReserva;
                        var qry_pjCJ2 = from p in db.Pasaje
                                        where p.IDReserva == aux2_idres_vuelta
                                        select p;
                        foreach (var pj in qry_pjCJ2)
                        {
                            //--------------------------------------PUNTAJES-----------------------------------//
                            //búsqueda del puntaje a ganar
                            var puntosAGanar = from pv in db.ProgramacionViaje
                                               join rxt in db.Ruta_x_UnidadTransporte on pv.IdRuta_x_UnidadTransporte equals rxt.IdRuta_x_UnidadTransporte
                                               join r in db.Ruta on rxt.IDRuta equals r.IDRuta
                                               where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                               select r.PuntosAGanar;
                            //Suma de puntaje 
                            Persona empresa = db.Persona.Find(aux_per.First().IDPersona);
                            empresa.PuntosAcumulados += puntosAGanar.First();
                            db.Entry(empresa).State = EntityState.Modified;


                            //--------------------------------------DESCUENTOS-----------------------------------//
                            //acumular pagos
                            monto_pago_total += pj.ProgramacionViaje.Precio;
                            //Buscar promocion asociada al viaje de cada pasaje
                            var qry_promocion = from pv in db.ProgramacionViaje
                                                join pxpv in db.Promocion_ProgramacionViaje on pv.IDProgramacionViaje equals pxpv.IDProgramacionViaje
                                                join p in db.Promocion on pxpv.IdPromocion equals p.IdPromocion
                                                where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                                select new { p.FechaFin, p.FechaInicio, p.PorcentajeDescuento, p.PuntosRequeridos, p.TipoCliente };
                            if (qry_promocion != null)
                            {
                                //Por cada promocion, verificar la fecha de fin 
                                foreach (var prom in qry_promocion)
                                {
                                    //Si es menor realizar descuento
                                    if (prom.FechaInicio < DateTime.Now.Date && prom.FechaFin > DateTime.Now.Date)
                                    {
                                        //Verificar que el descuento se aplica al tipo de cliente
                                        if (prom.TipoCliente == empresa.TipoPersona)
                                        {
                                            //si el cliente tiene puntaje para invertir
                                            if (empresa.PuntosAcumulados >= prom.PuntosRequeridos)
                                            {
                                                //acumular descuento
                                                monto_descuento_total += pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                                pj.MontoDescuento = pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                                empresa.PuntosAcumulados -= prom.PuntosRequeridos;
                                                db.Entry(empresa).State = EntityState.Modified;
                                                //si los descuentos acumulados superan al pago solo seran iguales a este en el caso extremo
                                                if (monto_descuento_total > monto_pago_total)
                                                {
                                                    monto_descuento_total = monto_pago_total;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }

                            }

                            //--------------------------------------MODIFICACIONES PASAJES-----------------------------------//
                            pj.MontoCosto = pj.ProgramacionViaje.Precio;
                            pj.MontoPago = pj.MontoCosto - pj.MontoDescuento;
                            pj.Estado = "CA";
                            db.Entry(pj).State = EntityState.Modified;
                        }

                        //--------------------------------------MODIFICAR RESERVA DE VUELTA-----------------------------------//

                        Reserva res_vuelta = db.Reserva.Find(aux2_idres_vuelta);
                        res_vuelta.Estado = "CA";
                        db.Entry(res_vuelta).State = EntityState.Modified;

                        //db.SaveChanges();
                    }
                }
                //Si el pagador NO es un Cliente Empresa
                else
                {
                    //Asignarle sus pasajes por cada uno
                    int aux_idres = (int)Session["MODVENTA_IDReserva"];
                    var qry_pjcn = from p in db.Pasaje
                                   where p.IDReserva == aux_idres
                                   select p;
                    foreach (var pj in qry_pjcn)
                    {
                        //--------------------------------------PUNTAJES-----------------------------------//
                        //búsqueda del puntaje a ganar
                        var puntosaganar = from pv in db.ProgramacionViaje
                                           join rxt in db.Ruta_x_UnidadTransporte on pv.IdRuta_x_UnidadTransporte equals rxt.IdRuta_x_UnidadTransporte
                                           join r in db.Ruta on rxt.IDRuta equals r.IDRuta
                                           where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                           select r.PuntosAGanar;
                        int? puntos = puntosaganar.First();
                        //búsqueda del pasajero asociado
                        Persona cliente = db.Persona.Find(pj.IDPersona);
                        //suma de puntaje
                        cliente.PuntosAcumulados += puntos;
                        //actualizar en bd
                        db.Entry(cliente).State = EntityState.Modified;

                        //--------------------------------------DESCUENTOS-----------------------------------//
                        //acumular pagos
                        monto_pago_total += pj.ProgramacionViaje.Precio;
                        //Buscar promocion asociada al viaje de cada pasaje
                        var qry_promocion = from pv in db.ProgramacionViaje
                                            join pxpv in db.Promocion_ProgramacionViaje on pv.IDProgramacionViaje equals pxpv.IDProgramacionViaje
                                            join p in db.Promocion on pxpv.IdPromocion equals p.IdPromocion
                                            where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                            select new { p.FechaFin, p.FechaInicio, p.PorcentajeDescuento, p.PuntosRequeridos, p.TipoCliente };
                        if (qry_promocion != null)
                        {
                            //Por cada promocion, verificar la fecha de fin 
                            foreach (var prom in qry_promocion)
                            {
                                //Si es menor realizar descuento
                                if (prom.FechaInicio < DateTime.Now.Date && prom.FechaFin > DateTime.Now.Date)
                                {
                                    //Buscar el tipo de persona/cliente para saber si la promoción es aplicable o no
                                    Persona cli = db.Persona.Find(pj.IDPersona);
                                    //Verificar que el descuento se aplica al tipo de cliente
                                    if (prom.TipoCliente == cliente.TipoPersona)
                                    {
                                        //si el cliente tiene puntaje para invertir
                                        if (cliente.PuntosAcumulados >= prom.PuntosRequeridos)
                                        {
                                            //acumular descuento
                                            monto_descuento_total += pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                            pj.MontoDescuento = pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                            cli.PuntosAcumulados -= prom.PuntosRequeridos;
                                            //si los descuentos acumulados superan al pago solo seran iguales a este en el caso extremo
                                            if (monto_descuento_total > monto_pago_total)
                                            {
                                                monto_descuento_total = monto_pago_total;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }

                        }

                        //--------------------------------------MODIFICACIONES PASAJES-----------------------------------//
                        pj.MontoCosto = pj.ProgramacionViaje.Precio;
                        pj.MontoPago = pj.MontoCosto - pj.MontoDescuento;
                        pj.Estado = "CA";
                    }
                    //db.SaveChanges();

                    //--------------------------------------------------------PASAJES DE VUELTA------------------------------------------------------------//
                    //Buscar reserva de vuelta
                    int aux2_idres = (int)Session["MODVENTA_IDReserva"];
                    var qry_res_vuelta = from p in db.Reserva
                                         where p.IdAnexo == aux2_idres
                                         select p;
                    //
                    if (qry_res_vuelta.Count() > 0)
                    {
                        //Asignarle los puntos asociados
                        int aux2_idres_vuelta = qry_res_vuelta.First().IDReserva;
                        var qry_pjCJ2 = from p in db.Pasaje
                                        where p.IDReserva == aux2_idres_vuelta
                                        select p;
                        foreach (var pj in qry_pjCJ2)
                        {
                            //--------------------------------------PUNTAJES-----------------------------------//
                            //búsqueda del puntaje a ganar
                            var puntosaganar = from pv in db.ProgramacionViaje
                                               join rxt in db.Ruta_x_UnidadTransporte on pv.IdRuta_x_UnidadTransporte equals rxt.IdRuta_x_UnidadTransporte
                                               join r in db.Ruta on rxt.IDRuta equals r.IDRuta
                                               where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                               select r.PuntosAGanar;
                            int? puntos = puntosaganar.First();
                            //búsqueda del pasajero asociado
                            Persona cliente = db.Persona.Find(pj.IDPersona);
                            //suma de puntaje
                            cliente.PuntosAcumulados += puntos;
                            //actualizar en bd
                            db.Entry(cliente).State = EntityState.Modified;

                            //--------------------------------------DESCUENTOS-----------------------------------//
                            //acumular pagos
                            monto_pago_total += pj.ProgramacionViaje.Precio;
                            //Buscar promocion asociada al viaje de cada pasaje
                            var qry_promocion = from pv in db.ProgramacionViaje
                                                join pxpv in db.Promocion_ProgramacionViaje on pv.IDProgramacionViaje equals pxpv.IDProgramacionViaje
                                                join p in db.Promocion on pxpv.IdPromocion equals p.IdPromocion
                                                where pv.IDProgramacionViaje == pj.IDProgramacionViaje
                                                select new { p.FechaFin, p.FechaInicio, p.PorcentajeDescuento, p.PuntosRequeridos, p.TipoCliente };
                            if (qry_promocion != null)
                            {
                                //Por cada promocion, verificar la fecha de fin 
                                foreach (var prom in qry_promocion)
                                {
                                    //Si es menor realizar descuento
                                    if (prom.FechaInicio < DateTime.Now.Date && prom.FechaFin > DateTime.Now.Date)
                                    {
                                        //Buscar el tipo de persona/cliente para saber si la promoción es aplicable o no
                                        Persona cli = db.Persona.Find(pj.IDPersona);
                                        //Verificar que el descuento se aplica al tipo de cliente
                                        if (prom.TipoCliente == cliente.TipoPersona)
                                        {
                                            //si el cliente tiene puntaje para invertir
                                            if (cliente.PuntosAcumulados >= prom.PuntosRequeridos)
                                            {
                                                //acumular descuento
                                                monto_descuento_total += pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                                pj.MontoDescuento = pj.ProgramacionViaje.Precio * (decimal)prom.PorcentajeDescuento / 100;
                                                cli.PuntosAcumulados -= prom.PuntosRequeridos;
                                                //si los descuentos acumulados superan al pago solo seran iguales a este en el caso extremo
                                                if (monto_descuento_total > monto_pago_total)
                                                {
                                                    monto_descuento_total = monto_pago_total;
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }

                            }

                            //-------------------------------MODIFICACIONES PASAJES-----------------------------//
                            pj.MontoCosto = pj.ProgramacionViaje.Precio;
                            pj.MontoPago = pj.MontoCosto - pj.MontoDescuento;
                            pj.Estado = "CA";
                        }

                        //--------------------------------------MODIFICAR RESERVA DE VUELTA-----------------------------------//

                        Reserva res_vuelta = db.Reserva.Find(aux2_idres_vuelta);
                        res_vuelta.Estado = "CA";
                        db.Entry(res_vuelta).State = EntityState.Modified;

                        //db.SaveChanges();
                    }
                }

                //--------------------------------------MODIFICAR RESERVA SOLO IDA O IDA-----------------------------------//
                int idres_ida = (int)Session["MODVENTA_IDReserva"];
                Reserva res = db.Reserva.Find(idres_ida);
                res.Estado = "CA";
                db.Entry(res).State = EntityState.Modified;

                //--------------------------------------AGREGAR VENTA-----------------------------------//

                //Buscar nota de credito y excluir las no existentes
                if (chbxNotaCred) //si no se usa nota de crédito, no entrar
                {
                    NotaCredito nota_cred = db.NotaCredito.Find(venta.IDNotaCredito);
                    if (nota_cred == null)
                    {
                        ModelState.AddModelError("ErrorNotaCredNull", "La Nota de Crétido no existe");
                        //Cuando el modelo no sea válido, cargar el cliente anteriormente buscado si hubo
                        Persona p_aux1 = (Persona)Session["MODVENTA_CJ"];
                        if (p_aux1 != null)
                        {
                            ViewBag.CJ_RUC = p_aux1.RUC;
                            ViewBag.CJ_RazonSocial = p_aux1.RazonSocial;
                            ViewBag.CJ_Direccion = p_aux1.Direccion;
                            ViewBag.CJ_Telefono = p_aux1.Telefono.ToString();
                            ViewBag.CJ_Email = p_aux1.Email;
                        }
                        return View(venta);
                    }
                    if (nota_cred.FechaLimite < DateTime.Now.Date)
                    {
                        ModelState.AddModelError("ErrorNotaCredNull", "La Nota de Crétido ya venció");
                        //Cuando el modelo no sea válido, cargar el cliente anteriormente buscado si hubo
                        Persona p_aux2 = (Persona)Session["MODVENTA_CJ"];
                        if (p_aux2 != null)
                        {
                            ViewBag.CJ_RUC = p_aux2.RUC;
                            ViewBag.CJ_RazonSocial = p_aux2.RazonSocial;
                            ViewBag.CJ_Direccion = p_aux2.Direccion;
                            ViewBag.CJ_Telefono = p_aux2.Telefono.ToString();
                            ViewBag.CJ_Email = p_aux2.Email;
                        }
                        return View(venta);
                    }
                }


                //Llaves involucradas
                aux_venta.IDVenta = venta.IDVenta;
                aux_venta.IDReserva = (int)Session["MODVENTA_IDReserva"];
                aux_venta.IDNotaCredito = (venta.IDNotaCredito == 0 && !chbxNotaCred ? null : venta.IDNotaCredito);
                aux_venta.IDPersona = null;
                //Medio de pago y montos parciales
                aux_venta.MedioPago = venta.MedioPago;
                aux_venta.MontoNotaCredito = venta.MontoNotaCredito;
                aux_venta.MontoSoles = (decimal?)venta.MontoSoles;
                aux_venta.MontoDescuento = monto_descuento_total;
                aux_venta.MontoDolares = (decimal?)venta.MontoDolares;
                aux_venta.MontoTarjeta = venta.MontoTarjeta;
                aux_venta.MontoEfectivo = (decimal?)aux_venta.MontoSoles + (decimal?)aux_venta.MontoDolares * tipo_cambio;
                aux_venta.Vuelto = (decimal)venta.Vuelto;
                //Montos totales e IGV
                aux_venta.Total = venta.Total;
                aux_venta.Subtotal = (decimal?)(Convert.ToDouble((decimal)aux_venta.Total / (1 + porc_igv)));
                aux_venta.IGV = aux_venta.Subtotal * porc_igv;

                //Otros campos
                aux_venta.Estado = "CA";
                aux_venta.FechaPago = DateTime.Now;

                db.Venta.Add(aux_venta);

                // PD: Daniel N., para guardar en documentoventa (factura)

                if (aux_per.Count() > 0) //si el pagador fue una empresa VALIDA
                {
                    DocumentoVenta documentoVenta = new DocumentoVenta();
                    documentoVenta.Total = aux_venta.Total;
                    documentoVenta.Subtotal = aux_venta.Subtotal;
                    documentoVenta.FechaPago = aux_venta.FechaPago;
                    documentoVenta.IGV = aux_venta.IGV;
                    documentoVenta.IDVenta = aux_venta.IDVenta;
                    documentoVenta.Estado = "AC";
                    documentoVenta.Venta = aux_venta; //enlace con venta
                    db.DocumentoVenta.Add(documentoVenta);
                }

                //Impresion de Pasajes


                db.SaveChanges(); // guardamos venta y se genera IDVenta

                return RedirectToAction("PrintPasajes", new { id = aux_venta.IDVenta });

            }

            //Cuando el modelo no sea válido, cargar el cliente anteriormente buscado si hubo
            Persona persona = (Persona)Session["MODVENTA_CJ"];
            if (persona != null)
            {
                ViewBag.CJ_RUC = persona.RUC;
                ViewBag.CJ_RazonSocial = persona.RazonSocial;
                ViewBag.CJ_Direccion = persona.Direccion;
                ViewBag.CJ_Telefono = persona.Telefono.ToString();
                ViewBag.CJ_Email = persona.Email;
            }


            return View(venta);
        }

        public ActionResult PrintPasajes(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
            }
            Venta venta = db.Venta.Find(id);
            if (venta == null)
            {
                return HttpNotFound();
            }
            return View(venta);
        }

        public ActionResult PrintFactura(int? id)
        {
            if (id == null)
            {
                return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest);
            }
            DocumentoVenta documentoventa = db.DocumentoVenta.Find(id);
            if (documentoventa == null)
            {
                return HttpNotFound();
            }
            return View(documentoventa);
        }

	}
}